package com.example.cadmin.utils.Netty;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.cadmin.Application;
import com.example.cadmin.entity.*;
import com.example.cadmin.mapper.ArchivesMapper;
import com.example.cadmin.service.*;
import com.example.cadmin.utils.DateFormat;
import com.google.common.base.Joiner;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import java.io.UnsupportedEncodingException;
import java.util.*;

@Slf4j
public class NettyServerHandler extends SimpleChannelInboundHandler<String> {
    //定义一个channle 组，管理所有的channel GlobalEventExecutor.INSTANCE) 是全局的事件执行器，是一个单例
    public static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    /**
     * 有客户端与服务器发生连接时执行此方法
     * 1.打印提示信息
     * 2.将客户端保存到 channelGroup 中
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) {
        Channel channel = ctx.channel();
        System.err.println("有新的客户端与服务器发生连接。客户端地址：" + channel.remoteAddress());
        channelGroup.add(channel);
    }

    /**
     * 当有客户端与服务器断开连接时执行此方法，此时会自动将此客户端从 channelGroup 中移除
     * 1.打印提示信息
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) {
        Channel channel = ctx.channel();
        System.err.println("有客户端与服务器断开连接。客户端地址：" + channel.remoteAddress());
        String clientIp = ctx.channel().remoteAddress().toString().split(":")[0].replace("/", "");
        HostService hostService = Application.ac.getBean(HostService.class);
        hostService.update(new UpdateWrapper<Host>().eq("ip", clientIp).set("connection_status", 0));
    }

    /**
     * 表示channel 处于活动状态
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        System.out.println(ctx.channel().remoteAddress() + " 处于活动状态");
    }

    /**
     * 表示channel 处于不活动状态
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        System.out.println(ctx.channel().remoteAddress() + " 处于不活动状态");
    }

    /**
     * 读取到客户端发来的数据数据
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String message) throws UnsupportedEncodingException, InterruptedException {
        // 静态方法注入bean解决方案
        HostService hostService = Application.ac.getBean(HostService.class);
        //获取到当前channel
        Channel channel = ctx.channel();
        String clientIp = Convert.toStr(channel.remoteAddress());
        System.err.println(DateFormatUtils.format(System.currentTimeMillis()
                , "yyyy-MM-dd HH:mm:ss:SSS") + "有客户端发来的数据。地址：" + clientIp + " 内容：" + message);
        Host host = hostService.getOne(new QueryWrapper<Host>().like("ip", clientIp.split(":")[0]
                .replace("/", "")));

        JSONObject cabinetParams = JSONUtil.parseObj(message);
        String cmdName = cabinetParams.getStr("return");
        if ("board_x".equals(cmdName)) {
            // 获取配置信息
            host.setConnectionStatus(1);
            hostService.updateById(host);
            return;
        }
    }

    /**
     * 处理异常
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        log.error("发生异常。异常信息：{}", cause.getMessage());
        //关闭通道
//        ctx.close();
    }

    /**
     * 扫描层封装方法
     */
    public void scanningUtil(String layer, List<String> currentLayerIdList, String number) {
        ArchivesService archivesService = Application.ac.getBean(ArchivesService.class);
        int index = 1;
        for (String id : currentLayerIdList) {
            log.info(id);
            if ("00000000".equals(id)) {
                Archives archives = archivesService.getOne(new QueryWrapper<Archives>().eq("current_layer", layer)
                        .eq("current_column", Convert.toStr(index)).eq("number", number));
                if (archives != null) {

                    archives.setStatus(1);
                    archivesService.updateById(archives);
                }
                log.info(Convert.toStr(index));
                index++;
                continue;
            }
            Archives archives = archivesService.getOne(new QueryWrapper<Archives>().eq("file_id", id));
            if (archives == null) {
                continue;
            }
            if (!layer.equals(archives.getCurrentLayer())) {
                archives.setCurrentLayer(layer);
            }
            if (!Convert.toStr(index).equals(archives.getCurrentColumn())) {
                archives.setCurrentColumn(Convert.toStr(currentLayerIdList.indexOf(id) + 1));
            }
            archives.setNumber(number);
            archives.setStatus(0);
            archivesService.updateById(archives);
            index++;
        }
    }
}